package com.example.aspect;

import com.example.annotation.Cache;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 缓存切面
 * 实现@Cache注解的功能
 */
@Aspect
@Component
public class CacheAspect {
    
    private static final Logger logger = LoggerFactory.getLogger(CacheAspect.class);
    
    // 简单的内存缓存实现
    private final ConcurrentHashMap<String, CacheEntry> cache = new ConcurrentHashMap<>();
    
    /**
     * 定义切点：所有带有@Cache注解的方法
     */
    @Pointcut("@annotation(com.example.annotation.Cache)")
    public void cachePointcut() {}
    
    /**
     * 环绕通知：实现缓存逻辑
     */
    @Around("cachePointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Cache cacheAnnotation = method.getAnnotation(Cache.class);
        
        // 生成缓存键
        String cacheKey = generateCacheKey(joinPoint, cacheAnnotation);
        
        // 检查缓存
        CacheEntry entry = cache.get(cacheKey);
        if (entry != null && !entry.isExpired()) {
            logger.info("缓存命中: {}", cacheKey);
            return entry.getValue();
        }
        
        // 缓存未命中，执行方法
        logger.info("缓存未命中，执行方法: {}", method.getName());
        long startTime = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long endTime = System.currentTimeMillis();
        
        // 将结果存入缓存
        long expireTime = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(cacheAnnotation.expire());
        cache.put(cacheKey, new CacheEntry(result, expireTime));
        
        logger.info("方法执行完成，耗时: {}ms，结果已缓存", endTime - startTime);
        return result;
    }
    
    /**
     * 生成缓存键
     */
    private String generateCacheKey(ProceedingJoinPoint joinPoint, Cache cacheAnnotation) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String methodName = signature.getMethod().getName();
        String className = signature.getDeclaringType().getSimpleName();
        
        // 简单的参数拼接
        Object[] args = joinPoint.getArgs();
        StringBuilder keyBuilder = new StringBuilder();
        if (!cacheAnnotation.prefix().isEmpty()) {
            keyBuilder.append(cacheAnnotation.prefix()).append(":");
        }
        keyBuilder.append(className).append(".").append(methodName);
        
        if (args.length > 0) {
            keyBuilder.append("(");
            for (int i = 0; i < args.length; i++) {
                if (i > 0) keyBuilder.append(",");
                keyBuilder.append(args[i]);
            }
            keyBuilder.append(")");
        }
        
        return keyBuilder.toString();
    }
    
    /**
     * 缓存条目内部类
     */
    private static class CacheEntry {
        private final Object value;
        private final long expireTime;
        
        public CacheEntry(Object value, long expireTime) {
            this.value = value;
            this.expireTime = expireTime;
        }
        
        public Object getValue() {
            return value;
        }
        
        public boolean isExpired() {
            return System.currentTimeMillis() > expireTime;
        }
    }
}
